package com.gaofans.vertx.boot.web.exception;

import com.gaofans.vertx.boot.web.route.RouteDefinition;
import com.gaofans.vertx.boot.web.route.RouterConfigurer;
import com.gaofans.vertx.boot.web.utils.UriUtil;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.handler.ErrorHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;

import java.util.List;
import java.util.Map;

/**
 * 全局异常配置类
 * @author GaoFans
 */
public class RouterExceptionConfigurer implements RouterConfigurer, ApplicationContextAware {

    private ExceptionHandlerDiscoverer handlerDiscoverer;

    private ApplicationContext applicationContext;

    private static final Logger LOG = LoggerFactory.getLogger(RouterExceptionConfigurer.class);

    public RouterExceptionConfigurer(ExceptionHandlerDiscoverer handlerDiscoverer) {
        this.handlerDiscoverer = handlerDiscoverer;
    }

    @Override
    public void accept(RouteDefinition definition, Route route) {
        Map<String, List<ExceptionHandlerDefinition>> exceptionHandlers = handlerDiscoverer.findExceptionHandler();
        int handlerCount = 0;
        for (String path : exceptionHandlers.keySet()) {
            if(UriUtil.match(path,definition.getPath())){
                List<ExceptionHandlerDefinition> exceptionHandlerDefinitions = exceptionHandlers.get(path);
                for (ExceptionHandlerDefinition exceptionHandlerDefinition : exceptionHandlerDefinitions) {
                    handlerCount++;
                    route.failureHandler(routingContext -> {
                        boolean has = false;
                        for (Class<? extends Throwable> cause : exceptionHandlerDefinition.getCauses()) {
                            if(routingContext.failure().getClass().equals(cause)){
                                has = true;
                                break;
                            }
                        }
                        if(has){
                            routingContext.response().setStatusCode(exceptionHandlerDefinition.getCode());
                            exceptionHandlerDefinition.getHandler().handle(routingContext);
                        }
                        routingContext.next();
                    });
                }
            }
        }
        if(handlerCount > 0){
            route.failureHandler(routingContext -> {
                if(!routingContext.response().ended()){
                    routingContext.response().end();
                }
            });
        }else {
            LOG.debug("未找到自定义ExceptionHandler，启用默认的ExceptionHandler");
            route.failureHandler(this.applicationContext.getBean(ErrorHandler.class));
        }
    }


    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
